data Unit = Unit 
data Plus α β = Inl α | Inr β 
data Pair α β = Pair { outl :: α, outr :: β } 
data Iso α β = Iso { fromData :: β → α, toData :: α → β }

class Generic g where
  unit :: g Unit
  plus :: (Rep α, Rep β ) ⇒ g (Plus α β )
  pair :: (Rep α, Rep β ) ⇒ g (Pair α β )
  datatype :: (Rep α) ⇒ Iso α β → g β
  char :: g Char
  int :: g Int

class Rep α where 
  rep :: (Generic g ) ⇒ g α 

instance Rep Unit where 
  rep = unit 
instance (Rep α, Rep β ) ⇒ Rep (Plus α β ) where 
  rep = plus 
instance (Rep α, Rep β ) ⇒ Rep (Pair α β ) where 
  rep = pair 
instance Rep Char where 
  rep = char 
instance Rep Int where 
  rep = int 
instance (Rep α) ⇒ Rep [ α ] where 
  rep = datatype (Iso fromList toList ) 

fromList :: [ α ] → Plus Unit (Pair α [ α ]) 
fromList [ ] = Inl Unit 
fromList (x : xs ) = Inr (Pair x xs ) 

toList :: Plus Unit (Pair α [ α ]) → [ α ] 
toList (Inl Unit ) = [ ] 
toList (Inr (Pair x xs )) = x : xs

type Bin = [ Bit ] 
data Bit = 0 | 1 deriving (Show ) 
bits :: (Enum α) ⇒ Int → α → Bin 

showBin :: (Rep α) ⇒ α → Bin 
showBin = appShowBin rep

instance Generic ShowBin where 
  unit = ShowBin (λx → [ ]) 
  plus = ShowBin (λx → case x of Inl l → 0 : showBin l 
                                 Inr r → 1 : showBin r ) 
  pair = ShowBin (λx → showBin (outl x ) ++ showBin (outr x )) 
  datatype iso = ShowBin (λx → showBin (fromData iso x )) 
  char = ShowBin (λx → bits 7 x ) 
  int = ShowBin (λx → bits 16 x )

